home *** CD-ROM | disk | FTP | other *** search
-
-
-
- PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111))))
-
-
-
- NNNNAAAAMMMMEEEE
- perlsec - Perl security
-
- DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
- Perl is designed to make it easy to program securely even
- when running with extra privileges, like setuid or setgid
- programs. Unlike most command line shells, which are based
- on multiple substitution passes on each line of the script,
- Perl uses a more conventional evaluation scheme with fewer
- hidden snags. Additionally, because the language has more
- builtin functionality, it can rely less upon external (and
- possibly untrustworthy) programs to accomplish its purposes.
-
- Perl automatically enables a set of special security checks,
- called _t_a_i_n_t _m_o_d_e, when it detects its program running with
- differing real and effective user or group IDs. The setuid
- bit in Unix permissions is mode 04000, the setgid bit mode
- 02000; either or both may be set. You can also enable taint
- mode explicitly by using the ----TTTT command line flag. This flag
- is _s_t_r_o_n_g_l_y suggested for server programs and any program
- run on behalf of someone else, such as a CGI script. Once
- taint mode is on, it's on for the remainder of your script.
-
- While in this mode, Perl takes special precautions called
- _t_a_i_n_t _c_h_e_c_k_s to prevent both obvious and subtle traps. Some
- of these checks are reasonably simple, such as verifying
- that path directories aren't writable by others; careful
- programmers have always used checks like these. Other
- checks, however, are best supported by the language itself,
- and it is these checks especially that contribute to making
- a set-id Perl program more secure than the corresponding C
- program.
-
- You may not use data derived from outside your program to
- affect something else outside your program--at least, not by
- accident. All command line arguments, environment
- variables, locale information (see the _p_e_r_l_l_o_c_a_l_e manpage),
- results of certain system calls (readdir, readlink, the
- gecos field of getpw* calls), and all file input are marked
- as "tainted". Tainted data may not be used directly or
- indirectly in any command that invokes a sub-shell, nor in
- any command that modifies files, directories, or processes.
- (IIIImmmmppppoooorrrrttttaaaannnntttt eeeexxxxcccceeeeppppttttiiiioooonnnn: If you pass a list of arguments to
- either system or exec, the elements of that list are NNNNOOOOTTTT
- checked for taintedness.) Any variable set to a value
- derived from tainted data will itself be tainted, even if it
- is logically impossible for the tainted data to alter the
- variable. Because taintedness is associated with each
- scalar value, some elements of an array can be tainted and
- others not.
-
- For example:
-
-
-
- Page 1 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111))))
-
-
-
- $arg = shift; # $arg is tainted
- $hid = $arg, 'bar'; # $hid is also tainted
- $line = <>; # Tainted
- $line = <STDIN>; # Also tainted
- open FOO, "/home/me/bar" or die $!;
- $line = <FOO>; # Still tainted
- $path = $ENV{'PATH'}; # Tainted, but see below
- $data = 'abc'; # Not tainted
-
- system "echo $arg"; # Insecure
- system "/bin/echo", $arg; # Secure (doesn't use sh)
- system "echo $hid"; # Insecure
- system "echo $data"; # Insecure until PATH set
-
- $path = $ENV{'PATH'}; # $path now tainted
-
- $ENV{'PATH'} = '/bin:/usr/bin';
- delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
-
- $path = $ENV{'PATH'}; # $path now NOT tainted
- system "echo $data"; # Is secure now!
-
- open(FOO, "< $arg"); # OK - read-only file
- open(FOO, "> $arg"); # Not OK - trying to write
-
- open(FOO,"echo $arg|"); # Not OK, but...
- open(FOO,"-|")
- or exec 'echo', $arg; # OK
-
- $shout = `echo $arg`; # Insecure, $shout now tainted
-
- unlink $data, $arg; # Insecure
- umask $arg; # Insecure
-
- exec "echo $arg"; # Insecure
- exec "echo", $arg; # Secure (doesn't use the shell)
- exec "sh", '-c', $arg; # Considered secure, alas!
-
- @files = <*.c>; # Always insecure (uses csh)
- @files = glob('*.c'); # Always insecure (uses csh)
-
- If you try to do something insecure, you will get a fatal
- error saying something like "Insecure dependency" or
- "Insecure $ENV{PATH}". Note that you can still write an
- insecure ssssyyyysssstttteeeemmmm or eeeexxxxeeeecccc, but only by explicitly doing
- something like the "considered secure" example above.
-
- LLLLaaaauuuunnnnddddeeeerrrriiiinnnngggg aaaannnndddd DDDDeeeetttteeeeccccttttiiiinnnngggg TTTTaaaaiiiinnnntttteeeedddd DDDDaaaattttaaaa
-
- To test whether a variable contains tainted data, and whose
- use would thus trigger an "Insecure dependency" message,
- check your nearby CPAN mirror for the _T_a_i_n_t._p_m module, which
-
-
-
- Page 2 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111))))
-
-
-
- should become available around November 1997. Or you may be
- able to use the following _i_s__t_a_i_n_t_e_d() function.
-
- sub is_tainted {
- return ! eval {
- join('',@_), kill 0;
- 1;
- };
- }
-
- This function makes use of the fact that the presence of
- tainted data anywhere within an expression renders the
- entire expression tainted. It would be inefficient for
- every operator to test every argument for taintedness.
- Instead, the slightly more efficient and conservative
- approach is used that if any tainted value has been accessed
- within the same expression, the whole expression is
- considered tainted.
-
- But testing for taintedness gets you only so far. Sometimes
- you have just to clear your data's taintedness. The only
- way to bypass the tainting mechanism is by referencing
- subpatterns from a regular expression match. Perl presumes
- that if you reference a substring using $1, $2, etc., that
- you knew what you were doing when you wrote the pattern.
- That means using a bit of thought--don't just blindly
- untaint anything, or you defeat the entire mechanism. It's
- better to verify that the variable has only good characters
- (for certain values of "good") rather than checking whether
- it has any bad characters. That's because it's far too easy
- to miss bad characters that you never thought of.
-
- Here's a test to make sure that the data contains nothing
- but "word" characters (alphabetics, numerics, and
- underscores), a hyphen, an at sign, or a dot.
-
- if ($data =~ /^([-\@\w.]+)$/) {
- $data = $1; # $data now untainted
- } else {
- die "Bad data in $data"; # log this somewhere
- }
-
- This is fairly secure because /\w+/ doesn't normally match
- shell metacharacters, nor are dot, dash, or at going to mean
- something special to the shell. Use of /.+/ would have been
- insecure in theory because it lets everything through, but
- Perl doesn't check for that. The lesson is that when
- untainting, you must be exceedingly careful with your
- patterns. Laundering data using regular expression is the
- _O_N_L_Y mechanism for untainting dirty data, unless you use the
- strategy detailed below to fork a child of lesser privilege.
-
-
-
-
- Page 3 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111))))
-
-
-
- The example does not untaint $data if use locale is in
- effect, because the characters matched by \w are determined
- by the locale. Perl considers that locale definitions are
- untrustworthy because they contain data from outside the
- program. If you are writing a locale-aware program, and
- want to launder data with a regular expression containing
- \w, put no locale ahead of the expression in the same block.
- See the SECURITY entry in the _p_e_r_l_l_o_c_a_l_e manpage for further
- discussion and examples.
-
- SSSSwwwwiiiittttcccchhhheeeessss OOOOnnnn tttthhhheeee """"####!!!!"""" LLLLiiiinnnneeee
-
- When you make a script executable, in order to make it
- usable as a command, the system will pass switches to perl
- from the script's #! line. Perl checks that any command
- line switches given to a setuid (or setgid) script actually
- match the ones set on the #! line. Some Unix and Unix-like
- environments impose a one-switch limit on the #! line, so
- you may need to use something like -wU instead of -w -U
- under such systems. (This issue should arise only in Unix
- or Unix-like environments that support #! and setuid or
- setgid scripts.)
-
- CCCClllleeeeaaaannnniiiinnnngggg UUUUpppp YYYYoooouuuurrrr PPPPaaaatttthhhh
-
- For "Insecure $ENV{PATH}" messages, you need to set
- $ENV{'PATH'} to a known value, and each directory in the
- path must be non-writable by others than its owner and
- group. You may be surprised to get this message even if the
- pathname to your executable is fully qualified. This is _n_o_t
- generated because you didn't supply a full path to the
- program; instead, it's generated because you never set your
- PATH environment variable, or you didn't set it to something
- that was safe. Because Perl can't guarantee that the
- executable in question isn't itself going to turn around and
- execute some other program that is dependent on your PATH,
- it makes sure you set the PATH.
-
- The PATH isn't the only environment variable which can cause
- problems. Because some shells may use the variables IFS,
- CDPATH, ENV, and BASH_ENV, Perl checks that those are either
- empty or untainted when starting subprocesses. You may wish
- to add something like this to your setid and taint-checking
- scripts.
-
- delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # Make %ENV safer
-
- It's also possible to get into trouble with other operations
- that don't care whether they use tainted values. Make
- judicious use of the file tests in dealing with any user-
- supplied filenames. When possible, do opens and such aaaafffftttteeeerrrr
- properly dropping any special user (or group!) privileges.
-
-
-
- Page 4 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111))))
-
-
-
- Perl doesn't prevent you from opening tainted filenames for
- reading, so be careful what you print out. The tainting
- mechanism is intended to prevent stupid mistakes, not to
- remove the need for thought.
-
- Perl does not call the shell to expand wild cards when you
- pass ssssyyyysssstttteeeemmmm and eeeexxxxeeeecccc explicit parameter lists instead of
- strings with possible shell wildcards in them.
- Unfortunately, the ooooppppeeeennnn, gggglllloooobbbb, and backtick functions
- provide no such alternate calling convention, so more
- subterfuge will be required.
-
- Perl provides a reasonably safe way to open a file or pipe
- from a setuid or setgid program: just create a child process
- with reduced privilege who does the dirty work for you.
- First, fork a child using the special ooooppppeeeennnn syntax that
- connects the parent and child by a pipe. Now the child
- resets its ID set and any other per-process attributes, like
- environment variables, umasks, current working directories,
- back to the originals or known safe values. Then the child
- process, which no longer has any special permissions, does
- the ooooppppeeeennnn or other system call. Finally, the child passes
- the data it managed to access back to the parent. Because
- the file or pipe was opened in the child while running under
- less privilege than the parent, it's not apt to be tricked
- into doing something it shouldn't.
-
- Here's a way to do backticks reasonably safely. Notice how
- the eeeexxxxeeeecccc is not called with a string that the shell could
- expand. This is by far the best way to call something that
- might be subjected to shell escapes: just never call the
- shell at all.
-
- use English;
- die "Can't fork: $!" unless defined $pid = open(KID, "-|");
- if ($pid) { # parent
- while (<KID>) {
- # do something
- }
- close KID;
- } else {
- my @temp = ($EUID, $EGID);
- $EUID = $UID;
- $EGID = $GID; # initgroups() also called!
- # Make sure privs are really gone
- ($EUID, $EGID) = @temp;
- die "Can't drop privileges"
- unless $UID == $EUID && $GID eq $EGID;
- $ENV{PATH} = "/bin:/usr/bin";
- exec 'myprog', 'arg1', 'arg2'
- or die "can't exec myprog: $!";
- }
-
-
-
- Page 5 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111))))
-
-
-
- A similar strategy would work for wildcard expansion via
- glob, although you can use readdir instead.
-
- Taint checking is most useful when although you trust
- yourself not to have written a program to give away the
- farm, you don't necessarily trust those who end up using it
- not to try to trick it into doing something bad. This is
- the kind of security checking that's useful for set-id
- programs and programs launched on someone else's behalf,
- like CGI programs.
-
- This is quite different, however, from not even trusting the
- writer of the code not to try to do something evil. That's
- the kind of trust needed when someone hands you a program
- you've never seen before and says, "Here, run this." For
- that kind of safety, check out the Safe module, included
- standard in the Perl distribution. This module allows the
- programmer to set up special compartments in which all
- system operations are trapped and namespace access is
- carefully controlled.
-
- SSSSeeeeccccuuuurrrriiiittttyyyy BBBBuuuuggggssss
-
- Beyond the obvious problems that stem from giving special
- privileges to systems as flexible as scripts, on many
- versions of Unix, set-id scripts are inherently insecure
- right from the start. The problem is a race condition in
- the kernel. Between the time the kernel opens the file to
- see which interpreter to run and when the (now-set-id)
- interpreter turns around and reopens the file to interpret
- it, the file in question may have changed, especially if you
- have symbolic links on your system.
-
- Fortunately, sometimes this kernel "feature" can be
- disabled. Unfortunately, there are two ways to disable it.
- The system can simply outlaw scripts with any set-id bit
- set, which doesn't help much. Alternately, it can simply
- ignore the set-id bits on scripts. If the latter is true,
- Perl can emulate the setuid and setgid mechanism when it
- notices the otherwise useless setuid/gid bits on Perl
- scripts. It does this via a special executable called
- ssssuuuuiiiiddddppppeeeerrrrllll that is automatically invoked for you if it's
- needed.
-
- However, if the kernel set-id script feature isn't disabled,
- Perl will complain loudly that your set-id script is
- insecure. You'll need to either disable the kernel set-id
- script feature, or put a C wrapper around the script. A C
- wrapper is just a compiled program that does nothing except
- call your Perl program. Compiled programs are not subject
- to the kernel bug that plagues set-id scripts. Here's a
- simple wrapper, written in C:
-
-
-
- Page 6 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111))))
-
-
-
- #define REAL_PATH "/path/to/script"
- main(ac, av)
- char **av;
- {
- execv(REAL_PATH, av);
- }
-
- Compile this wrapper into a binary executable and then make
- _i_t rather than your script setuid or setgid.
-
- See the program wwwwrrrraaaappppssssuuuuiiiidddd in the _e_g directory of your Perl
- distribution for a convenient way to do this automatically
- for all your setuid Perl programs. It moves setuid scripts
- into files with the same name plus a leading dot, and then
- compiles a wrapper like the one above for each of them.
-
- In recent years, vendors have begun to supply systems free
- of this inherent security bug. On such systems, when the
- kernel passes the name of the set-id script to open to the
- interpreter, rather than using a pathname subject to
- meddling, it instead passes /_d_e_v/_f_d/_3. This is a special
- file already opened on the script, so that there can be no
- race condition for evil scripts to exploit. On these
- systems, Perl should be compiled with
- -DSETUID_SCRIPTS_ARE_SECURE_NOW. The CCCCoooonnnnffffiiiigggguuuurrrreeee program that
- builds Perl tries to figure this out for itself, so you
- should never have to specify this yourself. Most modern
- releases of SysVr4 and BSD 4.4 use this approach to avoid
- the kernel race condition.
-
- Prior to release 5.003 of Perl, a bug in the code of
- ssssuuuuiiiiddddppppeeeerrrrllll could introduce a security hole in systems compiled
- with strict POSIX compliance.
-
- PPPPrrrrooootttteeeeccccttttiiiinnnngggg YYYYoooouuuurrrr PPPPrrrrooooggggrrrraaaammmmssss
-
- There are a number of ways to hide the source to your Perl
- programs, with varying levels of "security".
-
- First of all, however, you _c_a_n'_t take away read permission,
- because the source code has to be readable in order to be
- compiled and interpreted. (That doesn't mean that a CGI
- script's source is readable by people on the web, though.)
- So you have to leave the permissions at the socially
- friendly 0755 level. This lets people on your local system
- only see your source.
-
- Some people mistakenly regard this as a security problem.
- If your program does insecure things, and relies on people
- not knowing how to exploit those insecurities, it is not
- secure. It is often possible for someone to determine the
- insecure things and exploit them without viewing the source.
-
-
-
- Page 7 (printed 10/23/98)
-
-
-
-
-
-
- PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111)))) 22223333////JJJJuuuullll////99998888 ((((ppppeeeerrrrllll 5555....000000005555,,,, ppppaaaattttcccchhhh 00002222)))) PPPPEEEERRRRLLLLSSSSEEEECCCC((((1111))))
-
-
-
- Security through obscurity, the name for hiding your bugs
- instead of fixing them, is little security indeed.
-
- You can try using encryption via source filters (Filter::*
- from CPAN). But crackers might be able to decrypt it. You
- can try using the byte code compiler and interpreter
- described below, but crackers might be able to de-compile
- it. You can try using the native-code compiler described
- below, but crackers might be able to disassemble it. These
- pose varying degrees of difficulty to people wanting to get
- at your code, but none can definitively conceal it (this is
- true of every language, not just Perl).
-
- If you're concerned about people profiting from your code,
- then the bottom line is that nothing but a restrictive
- licence will give you legal security. License your software
- and pepper it with threatening statements like "This is
- unpublished proprietary software of XYZ Corp. Your access
- to it does not give you permission to use it blah blah
- blah." You should see a lawyer to be sure your licence's
- wording will stand up in court.
-
- SSSSEEEEEEEE AAAALLLLSSSSOOOO
- the _p_e_r_l_r_u_n manpage for its description of cleaning up
- environment variables.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Page 8 (printed 10/23/98)
-
-
-
-